package com.skt.utils;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.concurrent.TimeUnit;

@Component
public class RedisUtil {

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    // ========== 基础操作方法 ==========

    public void set(String key, Object value, long timeout, TimeUnit unit) {
        redisTemplate.opsForValue().set(key, value, timeout, unit);
    }

    public void set(String key, Object value) {
        redisTemplate.opsForValue().set(key, value);
    }

    public Object get(String key) {
        return redisTemplate.opsForValue().get(key);
    }

    public Boolean delete(String key) {
        return redisTemplate.delete(key);
    }

    public Boolean expire(String key, long timeout, TimeUnit unit) {
        return redisTemplate.expire(key, timeout, unit);
    }

    public Boolean hasKey(String key) {
        return redisTemplate.hasKey(key);
    }

    public Long increment(String key, long delta) {
        return redisTemplate.opsForValue().increment(key, delta);
    }

    // ========== Hash 操作方法 ==========

    public Long hDelete(String key, Object... fields) {
        return redisTemplate.opsForHash().delete(key, fields);
    }

    public Map<Object, Object> hEntries(String key) {
        return redisTemplate.opsForHash().entries(key);
    }

    public Long hSize(String key) {
        return redisTemplate.opsForHash().size(key);
    }

    public void hPut(String key, Object hashKey, Object value) {
        redisTemplate.opsForHash().put(key, hashKey, value);
    }

    public Object hGet(String key, Object hashKey) {
        return redisTemplate.opsForHash().get(key, hashKey);
    }

    public Boolean hHasKey(String key, Object hashKey) {
        return redisTemplate.opsForHash().hasKey(key, hashKey);
    }

    // ========== 分布式锁方法 ==========

    public Boolean tryLock(String lockKey, String requestId, long expireTime, TimeUnit unit) {
        return redisTemplate.opsForValue().setIfAbsent(lockKey, requestId, expireTime, unit);
    }

    public Boolean releaseLock(String lockKey, String requestId) {
        String currentValue = (String) redisTemplate.opsForValue().get(lockKey);
        if (requestId.equals(currentValue)) {
            return redisTemplate.delete(lockKey);
        }
        return false;
    }

    // ========== 新增方法（根据你的Service需求） ==========

    /**
     * 自增操作并设置过期时间
     */
    public Long increment(String key, long delta, long timeout, TimeUnit unit) {
        Long result = redisTemplate.opsForValue().increment(key, delta);
        if (result != null) {
            redisTemplate.expire(key, timeout, unit);
        }
        return result;
    }

    /**
     * Hash 删除指定字段
     */
    public void hDelete(String key, Object field) {
        redisTemplate.opsForHash().delete(key, field);
    }

    /**
     * 设置Hash多个字段
     */
    public void hPutAll(String key, Map<Object, Object> map) {
        redisTemplate.opsForHash().putAll(key, map);
    }

    /**
     * 获取Hash所有值
     */
    public List<Object> hValues(String key) {
        return redisTemplate.opsForHash().values(key);
    }

    /**
     * 如果不存在则设置Hash字段
     */
    public Boolean hPutIfAbsent(String key, Object hashKey, Object value) {
        return redisTemplate.opsForHash().putIfAbsent(key, hashKey, value);
    }

    /**
     * 使用Lua脚本实现原子比较删除
     */
    public Boolean compareAndDelete(String key, String expectedValue) {
        String luaScript =
                "if redis.call('get', KEYS[1]) == ARGV[1] then " +
                        "return redis.call('del', KEYS[1]) " +
                        "else " +
                        "return 0 " +
                        "end";

        DefaultRedisScript<Long> script = new DefaultRedisScript<>();
        script.setScriptText(luaScript);
        script.setResultType(Long.class);

        Long result = redisTemplate.execute(script, Collections.singletonList(key), expectedValue);
        return result != null && result > 0;
    }
}